#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<ctype.h> 

#define MAX 1024
#define SIZE 64
#define SPLIT " "
#define SkipSpace(pos) do{while(isspace(*pos)) pos++;}while(0)

#define NoneRedir 0
#define OutputRedir 1
#define AppendRedir 2
#define InputRedir 3
//#define DEBUG 1


int lastcode=0;
char cwd[MAX];
char enve[MAX];

int redir=NoneRedir;
char* filename=NULL;

const char* getUser()
{
    const char* name=getenv("USER"); 
    if(name) return name;
    else return "none";
}

const char* getHostName()
{

    const char* name=getenv("HOSTNAME"); 
    if(name) return name;
    else return "none";
}

const char* getCwd()
{
    const char* name=getenv("PWD"); 
    if(name) return name;
    else return "none";
}
char* homepath()
{
    char* str=getenv("HOME");
    if(str) return str;
    else return (char*)".";
}

void mcd(char* argv[])
{
     char* path=NULL; 
     if(argv[1]==NULL) path=homepath(); 
     else path=argv[1];
     chdir(path);
     char tmp[MAX];
     getcwd(tmp,sizeof(tmp));
     sprintf(cwd,"PWD=%s",tmp);
     putenv(cwd);
}

int getUserCommand(char* command,int num)
{
    printf("[%s@%s  %s]# ",getUser(),getHostName(),getCwd());
    char* ret=fgets(command,num,stdin);
    if(ret==NULL)
        return -1;
    command[strlen(command)-1]='\0';//去掉末尾的\n
    if(strlen(command))
    return 1;
    else 
    return -1;
}

void commandSplit(char* command,char* argv[])
{
    int argc=0;
    argv[argc++]=strtok(command,SPLIT);
    while(argv[argc++]=strtok(NULL,SPLIT));

#ifdef DEBUG 
    for(int i=0;i<argc-1;i++)
    {
        printf("%s\n",argv[i]);
    }
#endif 
}

void excute(char* argv[])
{
    pid_t id=fork();
    if(id<0)
    {
      perror("fork error:");
    }
    else if(id==0)
    {
        int fd=0;
        if(redir==InputRedir)
        {
            fd=open(filename,O_RDONLY);
            dup2(fd,0);
        }
        else if(redir==OutputRedir)
        {
            fd=open(filename,O_CREAT | O_WRONLY | O_TRUNC,0666);
            dup2(fd,1);
        }
        else if(redir==AppendRedir)
        {
            fd=open(filename,O_WRONLY | O_APPEND | O_CREAT,0666);
            dup2(fd,1);
        }
        execvp(argv[0],argv);
        exit(1);
    }
    else 
    {
       int status=0; 
       int ret= waitpid(id,&status,0);
       if(ret>0) lastcode=((status>>8)&0xFF);
    }
}

int doBuildin(char* argv[])
{
    if(strcmp(argv[0],"cd")==0)
    {
        mcd(argv); 
        return 1;
    }
    else if(strcmp(argv[0],"echo")==0)
    {
        if(argv[1])
        {
           if(*(argv[1])=='$'&&strlen(argv[0])>1)
           {   
                if(strcmp(argv[1]+1,"?")==0)
                {
                    printf("%d\n",lastcode);
                    lastcode=0;
                }
                else
                {
                    char* env=getenv(argv[1]+1);
                    if(env) printf("%s\n",env);
                    else printf("\n");
                }
                return 1;
           }
           else 
           {
               printf("%s\n",argv[1]);
               return 1;
           }
        }
        else 
        {
            printf("\n");
            return 1;
        }
    }
    else if(strcmp(argv[0],"export")==0)
    {
          if(argv[1])
          {
             strcpy(enve,argv[1]);
             putenv(enve);
          }
         return 1;
    }
    return 0;
}

void cheakdir(char* str,int n)
{
    redir=NoneRedir;
    char* end=str+n-1;
    char* start=str;
    while(end>=start)
    {
        if(*end=='>')
        {
            if(*(end-1)=='>')
            {
                redir=AppendRedir;
                filename=end+1;
                SkipSpace(filename);
                *(end-1)='\0';
                break;
            }
            else 
            {
                redir=OutputRedir;
                filename=end+1;
                *end='\0';
                SkipSpace(filename);
                break;
            }
        }
        else if(*end=='<')
        {
            redir=InputRedir;
            filename=end+1;
            *end='\0';
            SkipSpace(filename);
            break;
        }
        end--;
    }
}

int main()
{
    while(1)
    {
    //实现命令框
    char usercommand[MAX];
    char* argv[SIZE];
    int ret=getUserCommand(usercommand,sizeof(usercommand));
    //分割字符串
    if(ret==-1)
       continue;
    cheakdir(usercommand,strlen(usercommand));
    commandSplit(usercommand,argv);
    //判断是否为内建命令
    ret=doBuildin(argv);
    if(ret)
        continue;
    //运行代码 
    excute(argv);
    }
    return 0;
}
